package MapEditor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextField;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.doge.Settings;
import com.doge.Textures;
import com.doge.Tile;


public class EditorMain extends Game implements com.badlogic.gdx.ApplicationListener
{
	private Stage stage;
	int textureColSize = 3;
	String clickedTexture = null;
	String clickedMonster = null;
	//int    collision      = 15;
	GridSquare tiles[][] = new GridSquare[Settings.mapDim][Settings.mapDim];
	ArrayList<GridSquare> selectedTiles = new ArrayList<GridSquare>();
	//TODO: only use locations used in the tiles. 
	ArrayList<String> textureLocations = new ArrayList<String>();

	TextField  collisionField;
	
	GridTable mapTable;
	
	boolean displayGrid = true;
	
	
	class GridTable extends Table
	{
		ShapeRenderer shape = new ShapeRenderer();
		
		public void draw (SpriteBatch batch, float parentAlpha) 
		{
			super.draw(batch, parentAlpha);
			
			//draw rectangle around grid
			batch.end();
			shape.setProjectionMatrix(batch.getProjectionMatrix());
			shape.begin(ShapeType.Line);
			
			if(displayGrid)
			{
				shape.setColor(Color.BLACK);

				for(int x = 0; x < tiles.length; ++x)
				{
					shape.line((getX()-(getMinWidth()/2)-1) + (x*32), getY()-(getMinHeight()/2), 
							(getX()-(getMinWidth()/2)-1) + (x*32)   , getY()+(getMinHeight()/2));
					
					shape.line((getX()-(getMinWidth()/2)-1) , getY()-(getMinHeight()/2)+(x*32)+1, 
							(getX()+(getMinWidth()/2)-1)    , getY()-(getMinHeight()/2)+(x*32)+1);
				}
			}
			
			shape.setColor(Color.WHITE);
			
			//idk why there is a -1 or +1 .. it just makes it look better
			shape.rect(getX()-(getMinWidth()/2)-1, getY()-(getMinHeight()/2)+1, 
					getMinWidth(), getMinHeight());
			
			shape.end();
			batch.begin();
		}
	}
	
	public void loadMap(String mapPath) throws Exception
	{
		mapTable.clearChildren();
		//mapTable.debug();
		Tile[][] a = EditorFileOperations.LoadMapFromFile(mapPath).clone();
		
		int pixy = 700;
		for(int x = 0; x < Settings.mapDim*Settings.mapDim; ++x)
		{
			int i = x/Settings.mapDim;
			int y = x%Settings.mapDim;
		
			Tile t = a[i][y];
			t.pixx = 200+((x%Settings.mapDim)*32);
			t.pixy = pixy;
	
			//if(i == 0 || y == 0 || y == Settings.mapDim || x == Settings.mapDim )
			//	t.borderTile = true;	
			
			tiles[i][y] = new GridSquare(t);//,displayGrid);
			tiles[i][y].setBounds(t.pixx, pixy, 32, 32);
			tiles[i][y].addListener(new MapTileListener(tiles[i][y]));	
			mapTable.add(tiles[i][y]);
			
			if(y == (Settings.mapDim-1))
			{	
				mapTable.row();
				pixy -= 32;
			}
			
		}

	}
	
	public void deleteTile(GridSquare a)
	{
			a.t.occupied = false;
			a.t.character = null;
			a.t.textures.clear();	
	}
	
	class DeleteSelectedListener extends InputListener
	{
		public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
		{
			for(GridSquare a : selectedTiles)
			{
				deleteTile(a);
			}
			
			return false;
		}
	}
	
	class DeleteMonsterListener extends InputListener
	{
		public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
		{
			for(GridSquare a : selectedTiles)
			{
				a.t.character = null;
				a.t.occupied = false;
			}
			return false;
		}
	}
	
	public void deselectTile(GridSquare a)
	{
		a.isSelected = false;
		selectedTiles.remove(a);
	}
	
	public void deselectTiles()
	{
			for(GridSquare a : selectedTiles)
				a.isSelected = false;
			
			selectedTiles.clear();
	}
	
	public void deslectAll()
	{
		deselectTiles();
		clickedTexture = null;
		clickedMonster = null;
	}
	
	class TextureListener extends InputListener 
	{
		public String t = "";
		public TextureListener(String a) { this.t = a; }
		
		public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
		{
			/*Cursor image pixmap is not in RGBA8888 format.
			Pixmap pm = new Pixmap(Gdx.files.internal(t));
	        int xHotSpot = pm.getWidth() / 2;
	        int yHotSpot = pm.getHeight() / 2;
	        
	        Gdx.input.setCursorImage(pm, xHotSpot, yHotSpot);
	        pm.dispose();
	        */
			
			clickedTexture = t;
			clickedMonster = null;
			System.out.println("touchDown "+clickedTexture);
			return false;
		}
	}
	
	class MonsterListener extends InputListener 
	{
		public String t = "";
		public MonsterListener(String a) { this.t = a; }
		
		public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
		{
			
			clickedMonster = t;
			clickedTexture = null;
			System.out.println("touchDown "+clickedMonster);
			return false;
		}
	}
	
	class MapTileListener extends InputListener 
	{
		public GridSquare t;
		public MapTileListener(GridSquare a) 
		{ 
			this.t = a; 
		}
		
		public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) 
		{
			if(pointer == 0 && button == 1)
			{
				if(t.isSelected)
					deselectTile(t);
				/*else if(clickedTexture == null && clickedMonster == null)
				{
					if(t.t.textures.size() > 0 )
						t.t.textures.remove(t.t.textures.size()-1);
					else
					{
						t.t.occupied = false;
						t.t.character = null;
					}
				}else
				{
					clickedTexture = null;
					clickedMonster = null;
				}*/
				
				return false;
			}	
			
			collisionField.setText(Integer.toString(t.t.tileEntry_num));
			
			if(clickedTexture != null)
			{
				if(selectedTiles.size() == 0) selectedTiles.add(t);
			
				for(GridSquare a : selectedTiles)
				{
					a.addTexture(new TextureRegion(new Texture(clickedTexture)),
							textureLocations.indexOf(clickedTexture));
				}
				
				if(selectedTiles.size() == 1)
					deselectTile(t);
			}else if(clickedMonster != null)
			{
				if(selectedTiles.size() == 0) selectedTiles.add(t);
				
				for(GridSquare a : selectedTiles)
					try{
						Class<?> b = Class.forName("enemies."+clickedMonster);
						java.lang.reflect.Constructor<?> constructor = b.getConstructor(Tile.class);	
						a.t.character = (com.doge.Character)constructor.newInstance(new Object[]{a.t});
					
						a.t.occupied = true;
					}catch(Exception e)
					{
						e.printStackTrace();
					}
				
				if(selectedTiles.size() == 1)
					deselectTile(t);
			}else
			{
				selectedTiles.add(t);
				t.isSelected = true;
				return false;
			}
			
			
			
			for(GridSquare a : selectedTiles)
				System.out.println("Selected: " + a.t.x + ", "+ a.t.y);
			return false;
		}
		
	}
	
	public void create () 
	{
		stage = new Stage();
		Gdx.input.setInputProcessor(stage);
		Skin skin = new Skin(Gdx.files.internal("./bin/data/uiskin.json"));
		
		
		/*
		Label nameLabel = new Label("Name:", skin);

		TextureRegion upRegion = skin.getRegion("default-slider-knob");
		TextureRegion downRegion = skin.getRegion("default-slider-knob");
		BitmapFont buttonFont = skin.getFont("default-font");
		 */
		
		Table menuBar = new Table();
		Table table = new Table();
		Table table2 = new Table();
		Table toolMenu = new Table();
		Table monsterTable = new Table();
		Table monsterInternalTable = new Table();
		mapTable = new GridTable();
		
		stage.addActor(table2);
		stage.addActor(menuBar);
		stage.addActor(table);
		stage.addActor(toolMenu);
		stage.addActor(monsterInternalTable);
		stage.addActor(monsterTable);
		stage.addActor(mapTable);
		
		table.setFillParent(true);
		//table.debug();
		table.top();
		table.right();
		
		/*menu bar setup*/
		menuBar.setFillParent(true);
		//menuBar.debug();
		menuBar.top();
		menuBar.left();
		
		TextButton menuBarSave = new TextButton("Save",skin);
		TextButton menuBarLoad = new TextButton("Load",skin);
		TextButton menuBarClear = new TextButton("Clear",skin);
		TextButton menuBarGrid = new TextButton("Toggle Grid",skin);
		
		menuBar.add(menuBarSave);
		menuBar.add(menuBarLoad);
		menuBar.add(menuBarClear);
		menuBar.add(menuBarGrid);
		//add listeners
		
		/*tool menu setup*/
		toolMenu.setFillParent(true);
		toolMenu.bottom();
		toolMenu.right();
		
		TextButton toolDeselect = new TextButton("Deselect",skin);
		TextButton toolDeleteSelected = new TextButton("Delete Selected",skin);
		TextButton toolDeleteMonster = new TextButton("Delete Monster",skin);
		TextButton toolSetCollision = new TextButton("Set Collision",skin);
		TextButton toolFill = new TextButton("Fill",skin);
		collisionField  = new TextField("",skin);
		
		toolMenu.add(collisionField);
		toolMenu.row();
		toolMenu.add(toolSetCollision);
		toolMenu.add(toolDeselect);
		toolMenu.add(toolDeleteSelected);
		toolMenu.add(toolDeleteMonster);
		toolMenu.add(toolFill);
		
		toolFill.addListener(new InputListener(){
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				for(int i = 0; i < tiles.length; ++i)
					for(int j = 0; j < tiles[0].length; ++j)
						tiles[i][j].addTexture(new TextureRegion(new Texture(clickedTexture)),
								textureLocations.indexOf(clickedTexture));
				return false;
			}
		});
		
		//addlislteners
		menuBarGrid.addListener(new InputListener(){
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				displayGrid = !displayGrid;
				return false;
			}
		});
		
		menuBarLoad.addListener(new InputListener(){

			final String mapPath = "TESTMAP";
		
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				try{
					loadMap(mapPath);
				}catch(Exception e)
				{
					e.printStackTrace();
				}

				return false;
			}
		});
		
		menuBarSave.addListener(new InputListener(){

			final String mapPath = "TESTMAP";

			List<GridSquare> list = new ArrayList<GridSquare>();	    
			//Skin skin = new Skin(Gdx.files.internal("./bin/data/uiskin.json"));
			
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				/*Label label = new Label("FileName ",skin);
				TextButton b = new TextButton("Submit",skin);
				final TextField text = new TextField("",skin);*/
				
				
				
				//b.addListener(new InputListener(){	
					
					//public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
					//{
					list.clear();
						for (GridSquare[] array : tiles) 
							list.addAll(Arrays.asList(array));
						
						try{
							EditorFileOperations.SaveMapToFile(mapPath/*text.getText()*/, list, textureLocations);
						
						}catch(Exception e)
						{
							e.printStackTrace();
						}
						
						//return false;
					//}
				//});
				
				

				return false;
			}
		});
		
		menuBarClear.addListener(new InputListener(){
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				for(int i = 0; i < tiles.length; ++i)
					for(int j = 0; j < tiles[i].length; ++j)
						deleteTile(tiles[i][j]);
				selectedTiles.clear();
				return false;
			}
		});
		
		toolSetCollision.addListener(new InputListener(){
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				for(GridSquare a : selectedTiles)
					a.t.setCollision(Integer.parseInt(collisionField.getText()));
				return false;
			}
		});
		
		toolDeselect.addListener(new InputListener(){
			public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) 
			{
				deslectAll();
				return false;
			}
		});
		
		toolDeleteSelected.addListener(new DeleteSelectedListener());
		toolDeleteMonster.addListener(new DeleteMonsterListener());
		
		//map
		mapTable.setPosition(521,411);
		//mapTable.debug();
		int pixy = 700;
		for(int x = 0; x < Settings.mapDim*Settings.mapDim; ++x)
		{
			int i = x/Settings.mapDim;
			int y = x%Settings.mapDim;
		
			Tile t = new Tile(null,i,y);
			t.pixx = 200+((x%Settings.mapDim)*32);
			t.pixy = pixy;
	
			if(i == 0 || y == 0 || y == Settings.mapDim-1 || i == Settings.mapDim-1 )
			{
				t.borderTile = true;	
			}
			
			tiles[i][y] = new GridSquare(t);//,displayGrid);
			tiles[i][y].setBounds(t.pixx, pixy, 32, 32);
			tiles[i][y].addListener(new MapTileListener(tiles[i][y]));	
			mapTable.add(tiles[i][y]);
			
			if(y == (Settings.mapDim-1))
			{	
				mapTable.row();
				pixy -= 32;
			}
			
		}
		
		//monsterlist
		monsterTable.bottom();
		monsterTable.left();
		monsterTable.debug();
		//monsterTable.setPosition(100,100);
		monsterTable.setFillParent(true);
		//get all monsters
		
		FileHandle dirHandle;
		if (Gdx.app.getType() == ApplicationType.Android) {
		  dirHandle = Gdx.files.internal("enemies");
		} else {
		  // ApplicationType.Desktop ..
		  dirHandle = Gdx.files.internal("./bin/enemies");
		}
		
	    for (FileHandle f : dirHandle.list())
	    {
	    	if (!f.isDirectory())
	    	{
	    		TextButton button = new TextButton(f.name().replaceAll("(\\p{Ll})(\\p{Lu})","$1 $2")
	    											,skin);
	    		button.addListener(new MonsterListener(f.name()));
	    		monsterInternalTable.add(button);
	    		monsterInternalTable.row();
	    	}
	    }
	    ScrollPane monsterScrollPane = new ScrollPane(monsterInternalTable);
	    monsterTable.add(monsterScrollPane).height(300f);
	    
	    
	    
		//Going to need to separate textures into different map folders?
		/*texture menu setup*/
	    
		if (Gdx.app.getType() == ApplicationType.Android) {
		  dirHandle = Gdx.files.internal("data/mapTextures");
		} else {
		  // ApplicationType.Desktop ..
		  dirHandle = Gdx.files.internal("./bin/data/mapTextures");
		}
	
		int x = 0;
		for(FileHandle f : dirHandle.list())
		{
			if(f.isDirectory()) continue;
			
			// 	.nameWithoutExtension()
			ImageButton button = new ImageButton(new TextureRegionDrawable(new TextureRegion(new Texture("data/mapTextures/"+f.name()))));
			button.addListener(new TextureListener("data/mapTextures/"+f.name()));
			table2.add(button);
			
			textureLocations.add("data/mapTextures/"+f.name());
			
			if(x++ % textureColSize == 0)
				table2.row();
		}
		

		ScrollPane scroller = new ScrollPane(table2);
		table.add(scroller).height(700f);
	}

	public void resize (int width, int height) 
	{
		stage.setViewport(width, height, true);
	}

	public void render () 
	{
		Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
		stage.draw();
		
		//Table.drawDebug(stage);
	}

	public void dispose() 
	{
		stage.dispose();
	}
	
	

}
